package cn.com.ns.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;

import cn.com.ns.annotation.Controller;
import cn.com.ns.annotation.RequestMapping;
import cn.com.ns.annotation.RequestParam;
import cn.com.ns.annotation.ResponseBody;
import cn.com.ns.util.BeanUtils;
import cn.com.ns.util.DispatchActionConstant;
import cn.com.ns.util.RequestMapingMap;
import cn.com.ns.util.ScanClassUtil;
import cn.com.ns.util.View;
import cn.com.ns.util.WebContext;

@WebServlet(urlPatterns="*.do", 
initParams={
    @WebInitParam(name="basePackage", value="cn.com.ns.controller")
},
loadOnStartup=1
)
public class Dispatcherservlet extends HttpServlet {
	
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private String pareRequestURI(HttpServletRequest request){
		String path = request.getContextPath();
        String requestUri = request.getRequestURI();
        String midUrl = requestUri.replace(path, "");
        String lastUrl = midUrl.substring(0, midUrl.lastIndexOf("."));
		return lastUrl;
	}
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		pareRequestURI(request);
		System.out.println("发送get请求。。。。。。。。。。。");
		excute(request,response);
	}
 
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		resp.setContentType("text/html;charset=UTF-8");
		
		excute(req,resp);
	}
	
	private void excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        WebContext.requestHodler.set(request);
        WebContext.responseHodler.set(response);
        String requestUrl = pareRequestURI(request);
        Class<?> clazz = RequestMapingMap.getClassName(requestUrl);
        Object classInstance = BeanUtils.instanceClass(clazz);
        Method[] methods = BeanUtils.findDeclaredMethods(clazz);
        Method method = null;
        for (Method m : methods) {
            if (m.isAnnotationPresent(RequestMapping.class)) {
                String value = m.getAnnotation(RequestMapping.class).value();
                if (value != null && !"".equals(value.trim()) && requestUrl.equals(value.trim())) {
                    method = m;
                    break;
                }

            }

        }
        if (method != null) {
            Object retObject = null;
            try {
                Parameter[] params = method.getParameters();
                if(params.length<=0){
                	retObject = method.invoke(classInstance);
                }else{
                	List<Object> list = new ArrayList<Object>();
                	for(Parameter parameter : params){
                    	String typeName = parameter.toString();
                    	typeName = typeName.substring(0, typeName.indexOf(" "));
                    	try {
							Class catClass = Class.forName(typeName);
							Object obj = catClass.newInstance();
							if(parameter.isAnnotationPresent(RequestParam.class)){
								String param = parameter.getAnnotation(RequestParam.class).value();
								String key = request.getParameter(param);
								obj = key;
							}
							list.add(obj);
                    	} catch (ClassNotFoundException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (InstantiationException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
                    	
                    }
                	retObject = method.invoke(classInstance,list.toArray());
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
         
            if (retObject != null) {
                if(method.getAnnotation(ResponseBody.class) != null){
                	response.setContentType("text/x-javascript;charset=utf-8");
                	response.setHeader("cache-control", "no-cache");
                	PrintWriter out = response.getWriter();
                	Gson gson=new Gson();
                	String str=gson.toJson(retObject);
                	out.print(str);
                	out.flush();
                	out.close();
                	return;
                }
                View view = (View) retObject;
                if (view.getDispathAction().equals(DispatchActionConstant.FORWARD)) {
                    request.getRequestDispatcher(view.getUrl()).forward(request, response);
                } else if (view.getDispathAction().equals(DispatchActionConstant.REDIRECT)) {
                    response.sendRedirect(request.getContextPath() + view.getUrl());
                } else {
                    request.getRequestDispatcher(view.getUrl()).forward(request, response);
                }
            }


        }


    }
	
	public void init(ServletConfig config) throws ServletException{
		super.init(config);
		System.out.println("---初始化开始---");
		String basePackage = config.getInitParameter("basePackage");
		if(basePackage.indexOf(",")>0){
			String[] packageNameArr = basePackage.split(",");
			for(String packageName : packageNameArr){
				initRequestMapingMap(packageName);
			}
		}else{
			initRequestMapingMap(basePackage);
		}
		System.out.println("----初始化结束---");
	}
	
	private void initRequestMapingMap(String packageName){
        Set<Class<?>> setClasses =  ScanClassUtil.getClasses(packageName);
        for (Class<?> clazz :setClasses) {

            if (clazz.isAnnotationPresent(Controller.class)) {
                Method [] methods = BeanUtils.findDeclaredMethods(clazz);
                for(Method m:methods){
                    if(m.isAnnotationPresent(RequestMapping.class)){
                        String anoPath = m.getAnnotation(RequestMapping.class).value();
                        if(anoPath!=null && !"".equals(anoPath.trim())){
                            if (RequestMapingMap.getRequesetMap().containsKey(anoPath)) {
                                throw new RuntimeException("RequestMapping映射的地址不允许重复！");
                            }
                            RequestMapingMap.put(anoPath, clazz);
                        }
                    }
                }
            }
        }
	}
	
}
